package client;

import common.LogUtil;
import common.Protocol;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 本地服务连接实现
 */
public class ServiceConnection {
    private static final Logger logger = LogUtil.getLogger(ServiceConnection.class.getName());

    // 关联的服务管理器
    private final ServiceManager serviceManager;

    // 关联的本地服务
    private final LocalService localService;

    // 连接ID
    private final int connectionId;

    // 本地服务通道
    private SocketChannel localChannel;

    // 选择器
    private Selector selector;

    // 通信缓冲区
    private final ByteBuffer buffer = ByteBuffer.allocate(Protocol.BUFFER_SIZE);

    // 运行标志
    private volatile boolean running = false;

    /**
     * 构造函数
     */
    public ServiceConnection(ServiceManager serviceManager, LocalService localService, int connectionId) {
        this.serviceManager = serviceManager;
        this.localService = localService;
        this.connectionId = connectionId;
    }

    /**
     * 开始处理连接
     */
    public void start() throws IOException {
        if (running) {
            return;
        }

        // 创建本地服务连接
        localChannel = SocketChannel.open();
        localChannel.configureBlocking(false);

        // 连接到本地服务
        localChannel.connect(localService.getLocalAddress());

        // 初始化选择器
        selector = Selector.open();
        localChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

        // 设置运行标志
        running = true;

        // 开始数据传输
        serviceManager.getClient().getExecutor().execute(this::processData);
    }

    /**
     * 处理数据传输
     */
    private void processData() {
        try {
            while (running && localChannel.isOpen()) {
                selector.select(1000);

                if (!selector.isOpen()) {
                    break;
                }

                Iterator<SelectionKey> keys = selector.selectedKeys().iterator();

                while (keys.hasNext()) {
                    SelectionKey key = keys.next();
                    keys.remove();

                    if (!key.isValid()) {
                        continue;
                    }

                    if (key.isConnectable()) {
                        completeConnection();
                    }

                    if (key.isReadable()) {
                        readFromLocalService();
                    }
                }
            }
        } catch (Exception e) {
            logger.log(Level.WARNING, "Error processing data for connection: " + connectionId, e);
        } finally {
            close();
        }
    }

    /**
     * 完成连接过程
     */
    private void completeConnection() throws IOException {
        if (localChannel.finishConnect()) {
            logger.info("Connected to local service: " + localService.getConfig().getName() +
                    " for connection: " + connectionId);
        }
    }

    /**
     * 从本地服务读取数据
     */
    private void readFromLocalService() throws IOException {
        buffer.clear();
        int bytesRead = localChannel.read(buffer);

        if (bytesRead == -1) {
            // 连接关闭
            close();
            return;
        }

        if (bytesRead > 0) {
            buffer.flip();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);

            // 发送数据到服务器
            serviceManager.getClient().sendData(connectionId, data);
        }
    }

    /**
     * 向本地服务写入数据
     */
    public void writeToLocalService(byte[] data) throws IOException {
        if (!localChannel.isOpen()) {
            logger.warning("Attempt to write to closed channel, connection: " + connectionId);
            close();
            return;
        }

        ByteBuffer writeBuffer = ByteBuffer.wrap(data);
        while (writeBuffer.hasRemaining()) {
            localChannel.write(writeBuffer);
        }
    }

    /**
     * 关闭连接
     */
    public void close() {
        if (!running) {
            return;
        }

        running = false;

        try {
            if (localChannel != null && localChannel.isOpen()) {
                localChannel.close();
            }

            if (selector != null && selector.isOpen()) {
                selector.close();
            }

            // 从管理器中移除
            serviceManager.closeConnection(connectionId);

            logger.info("Local service connection closed: " + connectionId);
        } catch (IOException e) {
            logger.log(Level.WARNING, "Error closing local service connection: " + connectionId, e);
        }
    }

    /**
     * 获取连接ID
     */
    public int getConnectionId() {
        return connectionId;
    }

    /**
     * 获取本地服务
     */
    public LocalService getLocalService() {
        return localService;
    }
}
